#!/usr/bin/env python
#coding=utf-8

from multiprocessing import Process
import signal
from blueleakScan import blueleakscan
from scapy.all import *
import json
import ty_log

# -------------------------
# GLOBAL VARIABLES
# -------------------------
desc = {
        0: "Association Request", 
        1: "Association Response",
        2: "Reassociation Request",
        3: "Reassociation Response",
        4: "Probe Request",
        5: "Probe Response",
        8: "Beacon Frame",
        9: "ATIM",
        10: "Disassociation",
        11: "Authentication",
        12: "Deauthentication",
        13: "Acknowledgement",
    }

# the information whitelist need,you should confirm first
MACWhiteList=["06:5f:a7:76:75:d8","44:c8:74:ee:2f:7a","a8:15:4d:e2:b6:a8","04:5f:a7:5a:b5:f0"]
SSIDWhiteList=["JCG-6675D8-2.4G","1118","TY6"]
CHANNEL_SCAN=6

white_list={}
INVENTORY = {}
EXCLUDE = [None, "00:00:00:00:00:00", "ff:ff:ff:ff:ff:ff"]
aps = {}
#(INTERFACE, TYPE, LOG, SUBTYPE, DELAY, CHANNEL) = parseOptions(sys.argv[1:])
(INTERFACE, TYPE, LOG, SUBTYPE, DELAY, CHANNEL)=("wlp2s0",[0,1],"",[0,1,2,3,4,5,8,10,11,12,13],2,[11])

init_delay_time = int(time.time())

fakeap_list={}
#统计每种类型的帧数量
last_sc={}

init_sc_last_becon={}
fakeap_sc_time_list={}
fakeap_signal_time_list={}
#DOS VARIABLE
#接受到指定类型包的所有设备，但不是只要接受到了该设备就被攻击
devdic={}
#Deauth攻击
deauthAttackdic={}
#Disassociation攻击
disassociationAttackdic={}
#AuthAttack攻击
authAttackdic={}
authAttackTimes=0
#BeaconFloodAttack
beacnfloodAttack={}
unusualbeacnList=[]
beacnthreshold=50

#ProbeRequestAttack
proberequAttack={}
#AssociationAttack
associationAttack={}
#LogeOffAttack
logeOffAttack={}
#DataReplyAttack
DataReplyAttack={}

#not associated station
notAssociatedStation=[]
#delay_show
oldNotAssociatedStation=[]
#associated station
associatedStation={}
oldAssociatedStation={}
#合法bssid  to ssid
bssidToSsid={}
# probe ssid
probSsid=[]
'''
SC域,SequenceControl包含了SequenceNumber和FragmentNumber字段，fragmentnumber占低四位
每一个beancon帧的sequencenumber都比上一个+1，又因为低在beancon帧中为0，所以换成十进制SC每次都+16
'''

'''
伪ap的ssid和mac,append方式追加
'''
def update_fakeaplist(SSID, currentMAC,mac_check,pll,signal,sc,channel):
    reason = set()
    if mac_check==False:
        reason.add("mac not in whitelist")
    else:
        if pll == False:
            reason.add("pll error")
        if signal == False:
            reason.add("signal error")
        if sc == False:
            reason.add("sequence number error")
        if channel==False:
            reason.add("channel error")

    fakeap_list[SSID] = [currentMAC, reason]
    # if (SSID in fakeap_list.keys()):
    #     if (currentMAC not in fakeap_list[SSID]):
    #         fakeap_list[SSID].append([currentMAC,reason])
    # else:
    #     fakeap_list[SSID] = [currentMAC,reason]
'''
True:设备MAC在白名单中或者SSID不属于白名单
'''
def check_ssid_bssid_in_whitelist(SSID, currentMAC):
    res=True
    if (SSID in SSIDWhiteList):
        if (currentMAC not in MACWhiteList):
            res=False
    return res
'''
只处理设备MAC在白名单中的包
'''
def compare_sc_diff(packet):
    res=True
    current_mac=packet.addr2
    ssid=packet.info
    if(current_mac not in last_sc.keys()):
        last_sc[current_mac]=packet.SC
        return True

    lastSC = last_sc[current_mac]
    #print(lastSC)
    currentSC = packet.SC
    #print(currentSC)
    #检查到序列号不对后，对该热点的序列号进行更新,然后将该ap的错误次数+1
    if (abs(currentSC - lastSC)/16 > aps[current_mac][6]):
        #print abs(currentSC - lastSC)/16
        last_sc[current_mac] = currentSC
        if ssid in fakeap_sc_time_list.keys():
            fakeap_sc_time_list[ssid]+=1
        else:
            fakeap_sc_time_list[ssid]=1
        res=False
    else:
        last_sc[current_mac]=currentSC
    return res

def compare_signal_diff(signal,ssid,bssid):
    if signal < aps[bssid][4] or signal > aps[bssid][5]:
        signal_check = False
        if ssid in fakeap_signal_time_list.keys():
            fakeap_signal_time_list[ssid]+=1
        else:
            fakeap_signal_time_list[ssid]=1
    return True
def print_message():
    for i in INVENTORY:

        o_bssid = str(i)
        try:
            o_ssid = str(aps[i][0])
        except:
            o_ssid = ""
        try:
            o_channel = str(aps[i][1])
        except:
            o_channel = ""
        try:
            o_crypto = str("|".join(aps[i][2]))
        except:
            o_crypto = ""
        try:
            o_signal = str(aps[i][3])
        except:
            o_signal = ""
        o_client = str("|".join(INVENTORY[i]))
        try:
            o_min_signal = str(aps[i][4])
        except:
            o_min_signal = ""
        try:
            o_max_signal = str(aps[i][5])
        except:
            o_max_signal = ""
        OUT = o_bssid + "," + o_ssid + "," + o_channel + "," + o_crypto + "," + o_signal + "," + o_min_signal + "," + o_max_signal + "," + o_client
        if o_ssid !="":
            print OUT

# -------------------------
# SNIFFER INIT
# -------------------------
def sniffmgmt_init(p):
    global TYPE
    global SUBTYPE
    global LOG
    global DELAY
    global init_delay_time
    global f
    IP = []
    
    try:
        #p.show()
        SIGNAL = -(256-ord(p.notdecoded[-4:-3]))
        #p = pkt[Dot11Elt]
        cap = p.sprintf("{Dot11Beacon:%Dot11Beacon.cap%}"
                          "{Dot11ProbeResp:%Dot11ProbeResp.cap%}").split('+')
        
        BSSID = ""
        SSID, CHANNEL, PLL = None, None, None
        crypto = []
        pDot11Elt = None
        CLIENT = ""


        try: pDot11Elt= p[Dot11Elt]
        except: pass
        while isinstance(pDot11Elt, Dot11Elt):
            BSSID = p[Dot11].addr3
            PLL = p.len
            # if pDot11Elt.ID==3:
            #     try:
            #         CHANNEL = str(ord(p[Dot11][Dot11Elt][:3].info))
            #     except:
            #         pDot11Elt.show()
            #         print ord(pDot11Elt.info)
            #         p.show()
            #         print "** Error: " + str(traceback.format_exc())
            #         pass

            if pDot11Elt.ID == 0:
                SSID = p.info
            elif pDot11Elt.ID == 3:
                frequency = ord(p.notdecoded[2]) + ord(p.notdecoded[3]) * 256       #以十进制解析802.11数据包
                CHANNEL = (frequency - 2407) / 5
                # try:
                #     CHANNEL = str(ord(p[Dot11][Dot11Elt][:3].info))
                # except:
                #     CHANNEL = ord(pDot11Elt[0].info)
            elif pDot11Elt.ID == 48:
                crypto.append("WPA2")
            elif pDot11Elt.ID == 221 and pDot11Elt.info.startswith('\x00P\xf2\x01\x01\x00'):
                crypto.append("WPA")
            pDot11Elt = pDot11Elt.payload
        #新增加一个接入点
        if SSID != None and SSID != "" and BSSID not in aps and BSSID not in EXCLUDE:
            #print BSSID, SSID, CHANNEL, crypto, minsignal,maxsignal,SIGNAL,sequence_diff,len
            aps[BSSID] = [SSID, CHANNEL, crypto, SIGNAL,SIGNAL,SIGNAL,0,PLL]
        elif BSSID in aps:
            aps[BSSID][3] = SIGNAL
            if SIGNAL<aps[BSSID][4]:
                aps[BSSID][4]=SIGNAL
            if SIGNAL>aps[BSSID][5]:
                aps[BSSID][5]=SIGNAL
            aps[BSSID][7]=p.len
        
        IP.append(str(p.addr1))
        IP.append(str(p.addr2))
        IP.append(str(p.addr3))


        if p.subtype in SUBTYPE: # DEBUG
            pass
            #print p.type, p.subtype, IP, desc[p.subtype], SSID, CHANNEL, SIGNAL
        #return
        
        # TYPE = 0
        
        # BSSID, CLIENT, BSSID 
        if p.type == 0 and p.subtype == 0: # Association Request
            #print p.addr2, p.addr3
            CLIENT = p.addr2
            BSSID = p.addr1
        
        # CLIENT, BSSID, BSSID 
        if p.type == 0 and p.subtype == 1: # Association Response
            #print p.addr2, p.addr3
            CLIENT = p.addr1
            BSSID = p.addr2
        
        # CLIENT, FF: # + SSID (sometimes)
        if p.type == 0 and p.subtype == 4: # Probe Request
            #print p.addr2, p.addr3
            CLIENT = p.addr2

            if CLIENT not in notAssociatedStation and CLIENT not  in associatedStation.keys():
             notAssociatedStation.append(CLIENT)
            if CLIENT in associatedStation.keys() and CLIENT in notAssociatedStation:
                notAssociatedStation.remove(CLIENT)
            try:
                SSID = str(p.info)
                MAC_SSID = {}
                MAC_SSID["CLIENT"] = CLIENT
                MAC_SSID["SSID"] = SSID
                if len(SSID)>0 and MAC_SSID not in probSsid:
                    print MAC_SSID

                    probSsid.append(MAC_SSID)


                MAC_SSID = {}




            except: SSID = ""
        
        # CLIENT, BSSID, BSSID # + SSID
        if p.type == 0 and p.subtype == 5: # Probe Response
            #print p.addr2, p.addr3
            CLIENT = p.addr1
            BSSID = p.addr3

            try:
                SSID = str(p.info)

            except: SSID = ""
        
        # 00:, BSSID, BSSID # + SSID
        if p.type == 0 and p.subtype == 8: # Beacon Frame
            # CLIENT = p.addr2
            BSSID = p.addr2
            if BSSID in aps.keys():
                aps[BSSID][7] = p.len
            try:
                SSID = str(p.info)
                if BSSID in init_sc_last_becon.keys():
                    diff=abs(p.SC - init_sc_last_becon[BSSID])/16
                    #print diff
                    #print aps[BSSID][6]
                    init_sc_last_becon[BSSID]=p.SC
                    if diff < 500 and diff>aps[BSSID][6]:
                        aps[BSSID][6]=diff
                else:
                    init_sc_last_becon[BSSID]=p.SC
                    aps[BSSID][6]=0
            except: SSID = ""
        
        # BSSID, CLIENT, BSSID 
        if p.type == 0 and p.subtype == 10: # Disassociation
            #print p.addr2, p.addr3
            CLIENT = p.addr2
            BSSID = p.addr1
            if CLIENT  in associatedStation.keys():
                associatedStation.pop(CLIENT)

        # CLIENT, BSSID, BSSID 
        if p.type == 0 and p.subtype == 11: # Authentication
            #print p.addr2, p.addr3
            CLIENT = p.addr1
            BSSID = p.addr2


        # CLIENT, BSSID [re-check] (NOT IN BSSID?)
        if p.type == 0 and p.subtype == 13: # Acknowledgement | Action frames
            pass
            #print p.addr2, p.addr3
            #CLIENT = p.addr2
            #BSSID = p.addr1
        
        # TYPE = 1
        # BSSID, CLIENT, 00:

        if p.type == 1 and p.subtype == 10:
            #print p.addr2, p.addr3
            CLIENT = p.addr2
            BSSID = p.addr1
        
        # BSSID, CLIENT, 00: or CLIENT, BSSID, 00: [re-check] (NOT IN BSSID?)
        if p.type == 1 and p.subtype == 11: 
            pass
            #print p.addr2, p.addr3	
            #CLIENT = p.addr2
            #BSSID = p.addr1
        
        # CLIENT, 00:, 00: 
        if p.type == 1 and p.subtype == 12: 
            #print p.addr2, p.addr3	
            CLIENT = p.addr1
            #BSSID = p.addr1

        # TYPE = 2
        
        # CLIENT, BSSID, CLIENT
        if p.type == 2 and p.subtype == 0:
            if p.FCfield == 'to-DS':
                ap = p.addr3
                ssid = ""
                try:
                    ssid = str(p.info)
                except:
                    pass
                # if ap not in logeOffAttack.keys():
                #     logeOffAttack[ssid + ap] = 1
                # else:
                #     logeOffAttack[ssid + ap] = logeOffAttack[ssid + ap] + 1
            CLIENT = p.addr1  # p.addr1?
            BSSID = p.addr2
            
        # CLIENT, BSSID
        if p.type == 2 and p.subtype == 4:
            #print p.addr2, p.addr3
            CLIENT = p.addr2
            BSSID = p.addr3
        
        # BSSID, CLIENT, BSSID
        if p.type == 2 and p.subtype == 8:
            CLIENT = p.addr2
            BSSID = p.addr1
        
        # BSSID, CLIENT, BSSID
        if p.type == 2 and p.subtype == 12:
            #print p.addr2, p.addr3
            CLIENT = p.addr2
            BSSID = p.addr1

        # if  p.type==2:
        #      if p.FCfield & 0b010 != 0:    #from Ap
        #          if p.addr1 not in associatedStation.keys():
        #            associatedStation[p.addr1] = p.addr2
        #
        #      if p.FCfield&0b001!=0:          #to Ap
        #          if p.addr2 not in associatedStation.keys():
        #             associatedStation[p.addr2]=p.addr1



        if BSSID in EXCLUDE: BSSID = "" # CLEAN BSSID

        #注释print
        if BSSID not in INVENTORY and BSSID not in EXCLUDE and p.type == 0:
            INVENTORY[BSSID] = set()
            #print "added..." + str(BSSID)
            #print SSID
            if BSSID in aps:
                pass
                #print aps[BSSID]
            else:
                pass
                #print ">"+str(BSSID)+"??"
            #print
        #return
        
        if BSSID in INVENTORY and BSSID not in EXCLUDE and p.type in TYPE and p.subtype in SUBTYPE: 
            
            if CLIENT != BSSID and CLIENT not in EXCLUDE: INVENTORY[BSSID].add(CLIENT)

            check_delay_time = int(time.time()) - init_delay_time
            
            if LOG != "" and DELAY < check_delay_time:
                with open(LOG, 'w') as f:
                    f.write("")

            for i in INVENTORY:
                o_bssid = str(i)
                try: o_ssid = str(aps[i][0])
                except: o_ssid = ""
                try: o_channel = str(aps[i][1])
                except: o_channel = ""
                try: o_crypto = str("|".join(aps[i][2]))
                except: o_crypto = ""
                try: o_signal = str(aps[i][3])
                except: o_signal = ""
                o_client = str("|".join(INVENTORY[i]))
                try:o_min_signal=str(aps[i][4])
                except:o_min_signal=""
                try:o_max_signal=str(aps[i][5])
                except:o_max_signal=""
                OUT = o_bssid +","+ o_ssid +","+ o_channel +","+ o_crypto +","+ o_signal+","+ o_min_signal+","+ o_max_signal +","+ o_client
                #print OUT

                if LOG != "" and DELAY < check_delay_time:
                    with open(LOG, 'a') as f:
                        f.write(OUT + "\n")
            
            if DELAY < check_delay_time:
                init_delay_time = int(time.time())

        if SSID == "JCG-6675D8-2.4G" or BSSID == "06:5f:a7:76:75:d8":
            #print SSID," ",BSSID
            pass

        if BSSID not in bssidToSsid.keys() and BSSID!="" and SSID !=None:
            bssidToSsid[BSSID] = SSID

        if SSID not in  SSIDWhiteList:
            SSIDWhiteList.append(SSID)
            MACWhiteList.append(BSSID)
        return
    except Exception as e:
        pass
        print "** Error: " + str(traceback.format_exc())


# -------------------------
# SNIFFER
# -------------------------
def sniffmgm_check(p):
    global TYPE
    global SUBTYPE
    global LOG
    global DELAY
    global init_delay_time
    global f
    IP = []

    try:

        SIGNAL = -(256 - ord(p.notdecoded[-4:-3]))
        # p = pkt[Dot11Elt]
        cap = p.sprintf("{Dot11Beacon:%Dot11Beacon.cap%}"
                        "{Dot11ProbeResp:%Dot11ProbeResp.cap%}").split('+')

        BSSID = ""
        SSID, CHANNEL, PLL = None, None, None
        crypto = []
        pDot11Elt = None
        CLIENT = ""

        try:
            pDot11Elt = p[Dot11Elt]
        except:
            pass
        while isinstance(pDot11Elt, Dot11Elt):
            BSSID = p[Dot11].addr3
            PLL = p.len

            if pDot11Elt.ID == 0:
                SSID = p.info
            elif pDot11Elt.ID == 3:
                frequency = ord(p.notdecoded[2]) + ord(p.notdecoded[3]) * 256
                CHANNEL = (frequency - 2407) / 5
                # try:
                #     CHANNEL = str(ord(p[Dot11][Dot11Elt][:3].info))
                # except:
                #     CHANNEL = ord(pDot11Elt[0].info)
            elif pDot11Elt.ID == 48:
                crypto.append("WPA2")
            elif pDot11Elt.ID == 221 and pDot11Elt.info.startswith('\x00P\xf2\x01\x01\x00'):
                crypto.append("WPA")
            pDot11Elt = pDot11Elt.payload

        #新增加一个接入点
        if SSID != None and SSID != "" and BSSID not in aps and BSSID not in EXCLUDE:
            #print BSSID, SSID, CHANNEL, crypto, SIGNAL
            aps[BSSID] = [SSID, CHANNEL, crypto, SIGNAL, SIGNAL, SIGNAL, 0, PLL]
        elif BSSID in aps:
            aps[BSSID][3] = SIGNAL

        IP.append(str(p.addr1))
        IP.append(str(p.addr2))
        IP.append(str(p.addr3))

        if p.subtype in SUBTYPE:  # DEBUG
            pass
            # print p.type, p.subtype, IP, desc[p.subtype], SSID, CHANNEL, SIGNAL
        # return

        # TYPE = 0

        # BSSID, CLIENT, BSSID
        if p.type == 0 and p.subtype == 0:  # Association Request
            # print p.addr2, p.addr3
            CLIENT = p.addr2
            BSSID = p.addr1
            if BSSID not in associationAttack.keys():
                t = {}
                t[CLIENT] = 1
                associationAttack[BSSID] = t
            else:
                t = associationAttack[BSSID]
                if CLIENT in t.keys():
                    t[CLIENT] += 1
                else:
                    t[CLIENT] = 1
                associationAttack[BSSID] = t

        # CLIENT, BSSID, BSSID
        if p.type == 0 and p.subtype == 1:  # Association Response
            # print p.addr2, p.addr3
            CLIENT = p.addr1
            BSSID = p.addr2

        # CLIENT, FF: # + SSID (sometimes)
        if p.type == 0 and p.subtype == 4:  # Probe Request
            # print p.addr2, p.addr3
            CLIENT = p.addr2
            if CLIENT not in notAssociatedStation and CLIENT not  in associatedStation.keys():
             notAssociatedStation.append(CLIENT)

            if CLIENT in associatedStation.keys() and CLIENT in notAssociatedStation:
                notAssociatedStation.remove(CLIENT)
            try:
                SSID = str(p.info)

                srcadd = p.addr2
                if SSID != "":
                    if SSID not in proberequAttack.keys():
                        t = []
                        t.append(srcadd)
                        proberequAttack[SSID] = t
                    else:
                        t = proberequAttack[SSID]
                        if srcadd not in t:
                            t.append(srcadd)

                MAC_SSID = {}
                MAC_SSID["CLIENT"] = CLIENT
                MAC_SSID["SSID"] = SSID
                if len(SSID) > 0 and MAC_SSID not in probSsid:

                    probSsid.append(MAC_SSID)


            except:
                SSID = ""

        # CLIENT, BSSID, BSSID # + SSID
        if p.type == 0 and p.subtype == 5:  # Probe Response
            # print p.addr2, p.addr3
            CLIENT = p.addr1
            BSSID = p.addr3
            try:
                SSID = str(p.info)
            except:
                SSID = ""

        # 00:, BSSID, BSSID # + SSID
        if p.type == 0 and p.subtype == 8:  # Beacon Frame
            # print p.addr2, p.addr3
            # CLIENT = p.addr2
            BSSID = p.addr2
            try:
                SSID = str(p.info)

                dot11 = p[Dot11Elt]
                if len(dot11)<100:
                    unusualbeacnList.append(BSSID)
                else:
                    if SSID not in beacnfloodAttack.keys():
                        t=[];
                        t.append(BSSID)
                        beacnfloodAttack[""+SSID]=t;
                    else:
                        t=beacnfloodAttack[""+SSID]
                        if BSSID not in t:
                            t.append(BSSID)

                pll_check = True
                signal_check = True
                sc_check = True
                channel_check=True
                crypto_check=True
                if aps[BSSID][7]!=PLL:
                    pll_check = False
                if aps[BSSID][1]!=CHANNEL:
                    channel_check=False
                flag = check_ssid_bssid_in_whitelist(SSID, BSSID)

                #ssid在白名单，但是mac不在白名单
                if (flag == False):
                    update_fakeaplist(SSID, BSSID,False,pll_check,signal_check,sc_check,channel_check)
                #ssid bssid都在白名单
                elif SSID in SSIDWhiteList and BSSID in MACWhiteList:
                    if pll_check == False:
                        update_fakeaplist(SSID,BSSID,True,pll_check,signal_check,sc_check,channel_check)
                    if channel_check==False:
                        update_fakeaplist(SSID, BSSID, True, pll_check,signal_check, sc_check,channel_check)
                    signal_check=compare_signal_diff(SIGNAL,SSID,BSSID)
                    if (compare_sc_diff(p) == False):
                        sc_check = False

                    if sc_check == False:
                        update_fakeaplist(SSID, BSSID,True,pll_check,signal_check,sc_check,channel_check)
                    # if sc_check==True and signal_check==False:
                    #     update_fakeaplist(SSID,BSSID,True,sc_check,signal_check)
            except:
                SSID = ""

        # BSSID, CLIENT, BSSID
        if p.type == 0 and p.subtype == 10:  # Disassociation
            #print 'disasso found'
            # print p.addr2, p.addr3
            CLIENT = p.addr2
            BSSID = p.addr1
            destmac = p.addr1
            if destmac in disassociationAttackdic:
                disassociationAttackdic[destmac] += 1
            else:
                devdic[destmac] = 1
                disassociationAttackdic[destmac] = 1

        # CLIENT, BSSID, BSSID
        if p.type == 0 and p.subtype == 11:  # Authentication
            # print p.addr2, p.addr3
            CLIENT = p.addr1
            BSSID = p.addr2
            #p.show()
            destmac = p.addr1
            global authAttackTimes
            authAttackTimes += 1;

            if destmac in authAttackdic.keys():
                authAttackdic[destmac] += 1
            else:
                devdic[destmac] = 1
                authAttackdic[destmac] = 1

        # CLIENT, BSSID, BSSID
        if p.type == 0 and p.subtype == 12:  # Deauthentication
            destmac = p.addr1
            ap=p.addr2
            if ap in deauthAttackdic:
                deauthAttackdic[ap] += 1
            else:
                devdic[ap] = 1
                deauthAttackdic[ap] = 1

        # CLIENT, BSSID [re-check] (NOT IN BSSID?)
        if p.type == 0 and p.subtype == 13:  # Acknowledgement | Action frames
            pass
            # print p.addr2, p.addr3
            # CLIENT = p.addr2
            # BSSID = p.addr1

        # TYPE = 1

        # BSSID, CLIENT, 00:
        if p.type == 1 and p.subtype == 10:
            # print p.addr2, p.addr3
            CLIENT = p.addr2
            BSSID = p.addr1

        # BSSID, CLIENT, 00: or CLIENT, BSSID, 00: [re-check] (NOT IN BSSID?)
        if p.type == 1 and p.subtype == 11:
            pass
            # print p.addr2, p.addr3
            # CLIENT = p.addr2
            # BSSID = p.addr1

        # CLIENT, 00:, 00:
        if p.type == 1 and p.subtype == 12:
            # print p.addr2, p.addr3
            CLIENT = p.addr1
            # BSSID = p.addr1

        # TYPE = 2

        # CLIENT, BSSID, CLIENT
        if p.type == 2 and p.subtype == 0:
            # print p.addr2, p.addr3
            CLIENT = p.addr1  # p.addr1?
            BSSID = p.addr2

        # CLIENT, BSSID
        if p.type == 2 and p.subtype == 4:
            # print p.addr2, p.addr3
            CLIENT = p.addr2
            BSSID = p.addr3

        # BSSID, CLIENT, BSSID
        if p.type == 2 and p.subtype == 8:
            # print p.addr2, p.addr3
            # CLIENT = p.addr2
            # BSSID = p.addr1
            BSSID = ""
            CLIENT = ""
            if p.FCfield & 0b001 != 0:  # to-DS
                BSSID = p.addr1
                CLIENT = p.addr2
            else:  # from-DS
                BSSID = p.addr2
                CLIENT = p.addr1
            key = BSSID + "," + CLIENT
            fc = str(p.FCfield)
            # if BSSID == "c8:3a:35:23:46:b8":
            #     p.show()
            #     print fc, " ", p.FCfield


            #if fc.find("wep") > 0:
            if p.FCfield & 0x40 != 0 : #wep
                value = ""
                if len(p.wepdata) < 500:
                    value = p.wepdata
                else:
                    value = p.wepdata[0:500]
                if key not in DataReplyAttack.keys():
                    datas = {}
                    datas[value] = 1
                    DataReplyAttack[key] = datas
                else:
                    datas = DataReplyAttack[key]
                    if value not in datas.keys():
                        if len(datas.keys()) > 50:
                            tk = ""
                            tv = -1
                            # 为避免数据太大，每次快满的时候保存最大值
                            for k in datas.keys():
                                if datas[k] > tv:
                                    tv = datas[k]
                                    tk = k
                            datas.clear()
                            datas[tk] = tv
                            datas[value] = 1
                        else:
                            datas[value] = 0
                    else:
                        datas[value] += 1

        # BSSID, CLIENT, BSSID
        if p.type == 2 and p.subtype == 12:
            # print p.addr2, p.addr3
            CLIENT = p.addr2
            BSSID = p.addr1

        if p.type==2:   ####key:station Value:AP
             if p.addr1 != "" and p.addr2 != "":
                 if p.FCfield & 0x02 != 0:  # from Ap
                     if p.addr1 not in associatedStation.keys():
                         associatedStation[p.addr1] = p.addr2
                 if p.FCfield & 0x02 == 0:  # to Ap
                     if p.addr2 not in associatedStation.keys():
                         associatedStation[p.addr2] = p.addr1


        if BSSID in EXCLUDE: BSSID = ""  # CLEAN BSSID


        #注释print
        if BSSID not in INVENTORY and BSSID not in EXCLUDE and p.type == 0:
            INVENTORY[BSSID] = set()
            #print "added..." + str(BSSID)
            #print SSID
            if BSSID in aps:
                pass
                #print aps[BSSID]
            else:
                pass
                #print ">" + str(BSSID) + "??"
            #print

        # return

        if BSSID in INVENTORY and BSSID not in EXCLUDE and p.type in TYPE and p.subtype in SUBTYPE:

            if CLIENT != BSSID and CLIENT not in EXCLUDE: INVENTORY[BSSID].add(CLIENT)
            # return
            # print
            # print "START..."

            check_delay_time = int(time.time()) - init_delay_time

            if LOG != "" and DELAY < check_delay_time:
                with open(LOG, 'w') as f:
                    f.write("")

            for i in INVENTORY:

                o_bssid = str(i)
                try:
                    o_ssid = str(aps[i][0])
                except:
                    o_ssid = ""
                try:
                    o_channel = str(aps[i][1])
                except:
                    o_channel = ""
                try:
                    o_crypto = str("|".join(aps[i][2]))
                except:
                    o_crypto = ""
                try:
                    o_signal = str(aps[i][3])
                except:
                    o_signal = ""
                o_client = str("|".join(INVENTORY[i]))
                try:
                    o_min_signal = str(aps[i][4])
                except:
                    o_min_signal = ""
                try:
                    o_max_signal = str(aps[i][5])
                except:
                    o_max_signal = ""
                OUT = o_bssid + "," + o_ssid + "," + o_channel + "," + o_crypto + "," + o_signal + "," + o_min_signal + "," + o_max_signal + "," + o_client
                # print OUT

                if LOG != "" and DELAY < check_delay_time:
                    with open(LOG, 'a') as f:
                        f.write(OUT + "\n")

            if DELAY < check_delay_time:
                init_delay_time = int(time.time())

        if BSSID not in bssidToSsid.keys() and BSSID!="" and SSID !=None:
            bssidToSsid[BSSID] = SSID

        return
    except Exception as e:
        pass
        print "** Error: " + str(traceback.format_exc())
        print



# Channel hopper - This code is very similar to that found in airoscapy.py (http://www.thesprawl.org/projects/airoscapy/)
#需要在该函数中指定频道
def channel_hopper(interface):
    global CHANNEL_SCAN_
    os.system("iwconfig %s channel %d" % (interface, CHANNEL_SCAN))
    # while True:
    #     try:
    #         #channel = random.randrange(1,13)
    #         channel = random.choice(CHANNEL)
    #         os.system("iwconfig %s channel %d" % (interface, channel))
    #         time.sleep(1)
    #     except KeyboardInterrupt:
    #         break

def stop_channel_hop(signal, frame):
    # set the stop_sniff variable to True to stop the sniffer
    global stop_sniff
    stop_sniff = True
    channel_hop.terminate()
    channel_hop.join()

try:
    init_timeout=30
    print 'Please wait ' + str(init_timeout) + 's until the whitelist established successfully...'
    # channel_hop = Process(target = channel_hopper, args=(INTERFACE,))
    # channel_hop.start()
    # signal.signal(signal.SIGINT, stop_channel_hop)

    sniff(iface=INTERFACE, prn=sniffmgmt_init, timeout=init_timeout)

    white_list=aps
    print 'the ap list on channel '+str(CHANNEL_SCAN)+'is:'
    message = {}
    message["apList"] = aps
    ty_log.info(message)
    ty_log.send_to_syslog(json.dumps(message))
    for bssid in white_list.keys():
        print str(bssid),aps[bssid]
    print notAssociatedStation
    #加入ap名字，后排序

    # for key in associatedStation.keys():
    #     if associatedStation[key] in bssidToSsid.keys():
    #         associatedStation[key]=[associatedStation[key],bssidToSsid[associatedStation[key]]]
    #     else:
    #         associatedStation[key] = [associatedStation[key], ""]
    # associatedStation = sorted(associatedStation.items(), key=lambda x: x[1])
    # # print associatedStation
    # # print bssidToSsid
    # # print probSsid
    # message={}
    # message["notAssociatedStation"]=notAssociatedStation
    # ty_log.info(message)
    # ty_log.send_to_syslog(json.dumps(message))
    # message={}
    # message["associatedStation"]=associatedStation
    # ty_log.info(message)
    # ty_log.send_to_syslog(json.dumps(message))
    # message={}
    # message["probSsid"]=probSsid
    # ty_log.info(message)
    # ty_log.send_to_syslog(json.dumps(message))

    print 'The detector is running...'

    now_channel=13
    connected_devs={}
    while(True):
        now_channel += 1
        now_channel = now_channel % 14
        if now_channel==0:
            now_channel+=1
        os.system("iwconfig %s channel %d" % ("wlp2s0", now_channel))
        # not associated station
        notAssociatedStation = []
        # associated station
        associatedStation = {}
        #probssid
        probSsid=[]
        timeout=10
        devdic = {}
        deauthAttackdic = {}
        disassociationAttackdic = {}
        authAttackdic = {}
        authAttackTimes = 0
        last_sc={}
        fakeap_list={}
        fakeap_sc_time_list = {}
        fakeap_signal_time_list={}
        margin=timeout
        disass_dos_margin=6

        sniff(iface=INTERFACE, prn=sniffmgm_check, timeout=timeout)

        #white_list = aps
        print 'the ap list on channel ' + str(now_channel) + ' is:'
        ###
        # BeaconAttack
        ###
        beaconattack = {}
        beaconattacklist = []
        for ssid in beacnfloodAttack.keys():
            if len(beacnfloodAttack[ssid]) > 2 and ssid !='':
                beaconattacklist.append(ssid)
        beaconattack["BeaconFloodAttack"] = beaconattacklist
        if len(beaconattacklist)>0:
            print "----------------------------------BeaconAttack", json.dumps(beaconattack)
            message={}
            dosAttack={}
            dosAttack["type"] = "BeaconFloodAttack"
            dosAttack["victim"] = "FoundBeaconAttack"
            message["dosAttack"]=dosAttack
            ty_log.info(message)
            ty_log.send_to_syslog(json.dumps(message))
        elif len(beacnfloodAttack) > beacnthreshold or len(unusualbeacnList)>timeout:
            message = {}
            dosAttack = {}
            dosAttack["type"] = "BeaconFloodAttack"
            dosAttack["victim"] = "FoundBeaconAttack"
            message["dosAttack"] = dosAttack
            ty_log.info(message)
            ty_log.send_to_syslog(json.dumps(message))
        beacnfloodAttack={}
        for ssid in beaconattacklist:
            temp=[]
            for keys in aps.keys():
                t=aps[keys]
                if ssid == t[0]:
                    temp.append(keys)
            for key in temp:
                aps.pop(key)
        for mac in unusualbeacnList:
            if mac in aps.keys():
                aps.pop(mac)
        unusualbeacnList=[]

        message = {}
        message["apList"] = aps

        ty_log.info(message)
        ty_log.send_to_syslog(json.dumps(message))
        for bssid in white_list.keys():
            print str(bssid), aps[bssid]

        print 'sniff finished'
        #加入ap名字，后排序

        for key in associatedStation.keys():
            if key == "ff:ff:ff:ff:ff:ff":
                continue
            ap=associatedStation[key]
            ssid=""
            if ap in bssidToSsid.keys():
                ssid=bssidToSsid[ap]
            else:
                if ap in aps.keys():
                    ssid = aps[ap][0]
            if ssid=="":

                continue
            k=ssid+";"+ap
            if k not in connected_devs.keys():
                t=[]
                t.append(key)
                connected_devs[k]=t
            else:
                t=connected_devs[k]
                if key not in t:
                    t.append(key)
                connected_devs[k]=t

        if now_channel == 1 :
            for k in connected_devs.keys():
                v = connected_devs[k]
                for item in v:
                    for t1 in connected_devs.keys():
                        if t1 == k:
                            continue
                        if item in connected_devs[t1]:
                            connected_devs[t1].remove(item)
            mesg={}
            mesg["associatedStation"]=connected_devs
            ty_log.info(mesg)
            ty_log.send_to_syslog(json.dumps(mesg))
            connected_devs={}

        associatedStation=sorted(associatedStation.items(),key=lambda x:x[1])

        message = {}
        message["notAssociatedStation"] = notAssociatedStation
        ty_log.info(message)
        ty_log.send_to_syslog(json.dumps(message))
        # message = {}
        # message["associatedStation"] = associatedStation
        # ty_log.info(message)
        # ty_log.send_to_syslog(json.dumps(message))
        message = {}
        message["probSsid"] = probSsid
        ty_log.info(message)
        ty_log.send_to_syslog(json.dumps(message))
        oldAssociatedStation=associatedStation
        oldNotAssociatedStation=notAssociatedStation
        for ssid in fakeap_list.keys():
            # 1.sc错误次数和signal错误次数都不在范围内，才判断为假，
            # 2.mac地址不再白名单判断，判断为假
            # 报错是因为有可能一次都没错，出现key error
            if "mac not in whitelist" in fakeap_list[ssid][1]:
                print '[+]Found fake ap！'
                print ssid, fakeap_list[ssid]
                ap = []
                ap.append(ssid)
                ap.append("mac not in whitelist")
                message = {}
                message["fakeAp"] = ap
                ty_log.info(message)
                ty_log.send_to_syslog(json.dumps(message))
            if ssid in fakeap_sc_time_list.keys() and fakeap_sc_time_list[ssid]>margin and ssid in fakeap_signal_time_list.keys() and fakeap_signal_time_list[ssid]>margin:
                print '[+]Found fake ap！'
                print ssid,fakeap_list[ssid]

        #devdic为所有接收到可疑数据包的设备列表
        #dos attack cnt
        dosAttack={}
        #0 type
        #1 victim
        dosAttack["type"]="None"
        dosAttack["victim"]="None"
        for k, v in devdic.items():
            # print('dev is',k)
            destmac = k

            if (destmac in disassociationAttackdic):
                #mdk3 interface d -B AP
                if disassociationAttackdic[destmac] >= disass_dos_margin and destmac in aps.keys():
                    print('[+]Disassociation attack found,the victim is', destmac)
                    dosAttack["type"] = "DisassociationAttack"
                    # Disassociation攻击
                    dosAttack["victim"]=destmac
                    message = {}
                    message["dosAttack"] = dosAttack
                    ty_log.info(message)
                    ty_log.send_to_syslog(json.dumps(message))

            #aireplay-ng -0 0 -a ap interface
            if (destmac in deauthAttackdic):
                if deauthAttackdic[destmac] > timeout * 6:
                    print('[+]Deauth attack found,the victim is ', destmac)
                    dosAttack["type"] = "deauthAttackdic"
                    # Deauth攻击
                    dosAttack["victim"] = destmac
                    message = {}
                    message["dosAttack"] = dosAttack
                    ty_log.info(message)
                    ty_log.send_to_syslog(json.dumps(message))

        #mdk3 interface a -a ap
        authAttackList=[]
        for mac in authAttackdic.keys():
            if authAttackdic[mac] > 8*timeout:
                authAttackList.append(mac)
        if len(authAttackList)>0:
            for mac in authAttackList:
                dosAttack["type"] = "authAttackdic"
                # Auth攻击
                dosAttack["victim"] = mac
                message = {}
                message["dosAttack"] = dosAttack
                ty_log.info(message)
                ty_log.send_to_syslog(json.dumps(message))
        authAttackdic={}

        #mdk4 intserface p -e ssid
        probereqlist = []
        for ssid in proberequAttack.keys():
            t = proberequAttack[ssid]
            if len(t) > timeout:
                probereqlist.append(ssid)
        if len(probereqlist)>0:
            print "ProbeReqAtk Found!"
            for ssid in probereqlist:
                message = {}
                dosAttack = {}
                dosAttack["type"] = "proberequAttack"
                # 探测请求攻击
                dosAttack["victim"] = ssid
                message["dosAttack"] = dosAttack
                ty_log.info(message)
                ty_log.send_to_syslog(json.dumps(message))
        proberequAttack={}

        # AssociationAttack
        # Code
        associationList = []
        for key in associationAttack:
            t = associationAttack[key]
            flag = False
            for mac in t.keys():
                if t[mac] > timeout / 5:  # 现有网卡功率下的阈值，以后需要调整!!!!!!!!!!
                    associationList.append(key)
                    flag = True
                    break
            if flag != True:
                if len(t.keys()) >= timeout / 5:  # 现有网卡功率下的阈值，以后需要调整!!!!!!!!!!
                    associationList.append(key)
        if len(associationList)>0:
            for ap in associationList:
                dosAttack["type"] = "associationAttack"
                #关联攻击
                dosAttack["victim"] = ap
                message = {}
                message["dosAttack"] = dosAttack
                ty_log.info(message)
                ty_log.send_to_syslog(json.dumps(message))
        associationAttack={}

        #DataReplyAttacked mdk4 interface m -t ap -j
        DataReplyAttackList = []
        DataReplyTemp = {}
        for apmac in DataReplyAttack.keys():
            t10 = 0
            t50 = 0
            ap = apmac[0:apmac.index(",")]
            datas = DataReplyAttack[apmac]
            for k in datas:
                if datas[k] >= 50:
                    t50 += 1
                    break
                elif datas[k] > 10:
                    t10 += 1
            if t50 > 0:
                DataReplyAttackList.append(ap)
            if t10 > 0:
                if ap not in DataReplyTemp.keys():
                    DataReplyTemp[ap] = 1
                else:
                    DataReplyTemp[ap] += 1
        for ap in DataReplyTemp.keys():
            if DataReplyTemp[ap] > 2 and ap not in DataReplyAttackList:
                DataReplyAttackList.append(ap)
        for mac in DataReplyAttackList:
            dosAttack["type"] = "DataReplyAttack"
            # QoS数据重放攻击
            dosAttack["victim"] = mac
            message = {}
            message["dosAttack"] = dosAttack
            ty_log.info(message)
            ty_log.send_to_syslog(json.dumps(message))
        DataReplyAttack = {}

        print('current scan is done,the next will begin')
        print('--------------------------------------------------------------')
except Exception as e:
    print str(e)
    print "** CheckError: " + str(traceback.format_exc())


